package org.biubiu0002.baiblog.core.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import org.biubiu0002.baiblog.common.constants.CacheConstants;
import org.biubiu0002.baiblog.core.model.entity.GroupInfoEntity;
import org.biubiu0002.baiblog.core.model.vo.UserInfoVo;
import org.biubiu0002.baiblog.core.model.vo.res.GroupInfoResVo;
import org.biubiu0002.baiblog.core.service.ConversationService;
import org.biubiu0002.baiblog.core.service.GroupInfoService;
import org.biubiu0002.baiblog.core.service.GroupUserService;
import org.biubiu0002.baiblog.core.service.SysUserService;
import org.biubiu0002.baiblog.im.constants.MessageConstants;
import org.biubiu0002.baiblog.im.dto.conversation.ConversationCardDto;
import org.biubiu0002.baiblog.im.dto.conversation.ConversationInfoDto;
import org.biubiu0002.baiblog.im.dto.conversation.ConversationMessageItemDto;
import org.biubiu0002.baiblog.im.dto.conversation.ConversationUserInfoDto;
import org.biubiu0002.baiblog.im.dto.message.Message;
import org.biubiu0002.baiblog.im.dto.message.MessageRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author: biubiu0002
 * @Date: 2022/11/21 17:29
 **/
@Service
public class ConversationServiceImpl implements ConversationService {

    @Resource
    private SysUserService sysUserService;

    @Resource
    private GroupInfoService groupInfoService;

    @Resource
    private GroupUserService groupUserService;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Override
    public ConversationCardDto getConversationCard(String uid) {
        ConversationCardDto conversationCardDto = new ConversationCardDto();
        String latestConversationKey = CacheConstants.getLatestConversationKey(uid);
        String unreadKey = CacheConstants.getUnreadKey(uid);
        Map<Object, Object> unreadMap = redisTemplate.opsForHash().entries(unreadKey);
        Map<Object, Object> latestConversationMap = redisTemplate.opsForHash().entries(latestConversationKey);
        List<ConversationInfoDto> list = new ArrayList<>(latestConversationMap.size());
        Map<String, ConversationUserInfoDto> conversationUserInfoDtoMap= new HashMap<>(16);
        int totalUnread = 0;
        for (Map.Entry<Object, Object> entry : latestConversationMap.entrySet()) {
            //key is sessionId
            String key = (String) entry.getKey();
            String value = (String) entry.getValue();
            ConversationInfoDto conversationInfoDto = new ConversationInfoDto();
            ConversationMessageItemDto conversationMessageItemDto = JSON.parseObject(value, new TypeReference<ConversationMessageItemDto>() {
            });
            //角色码
            Integer sessionRole = conversationMessageItemDto.getSessionRole();

            int unreadCount = 0;
            if (unreadMap.get(key) != null) {
                unreadCount = Integer.parseInt((String) unreadMap.get(key));
                conversationInfoDto.setNewMessageCount(unreadCount);
                totalUnread += unreadCount;

            }
            conversationInfoDto.setAdd(unreadCount > 0);
            if(sessionRole==1){
                //私聊
                UserInfoVo userInfoVo = sysUserService.getUserInfoByUserUid(key);
                conversationInfoDto.setAvatar(userInfoVo.getAvatar());
                conversationInfoDto.setNickname(userInfoVo.getNickname());
                ConversationUserInfoDto conversationUserInfoDto = new ConversationUserInfoDto();
                conversationUserInfoDto.setUid(userInfoVo.getUserUid());
                conversationUserInfoDto.setNickname(userInfoVo.getNickname());
                conversationUserInfoDto.setAvatar(userInfoVo.getAvatar());
                conversationUserInfoDtoMap.put(userInfoVo.getUserUid(),conversationUserInfoDto);
            }
            else if(sessionRole ==2){
                //群聊
                GroupInfoResVo groupInfo = groupInfoService.getGroupInfo(key);
                List<UserInfoVo> userInfoVos = groupInfo.getUserInfoVos();
                for (UserInfoVo userInfoVo : userInfoVos) {
                    ConversationUserInfoDto conversationUserInfoDto = new ConversationUserInfoDto();
                    conversationUserInfoDto.setUid(userInfoVo.getUserUid());
                    conversationUserInfoDto.setNickname(userInfoVo.getNickname());
                    conversationUserInfoDto.setAvatar(userInfoVo.getAvatar());
                    conversationUserInfoDtoMap.put(userInfoVo.getUserUid(),conversationUserInfoDto);
                }
                conversationInfoDto.setAvatar(groupInfo.getGroupInfo().getAvatar());
                conversationInfoDto.setNickname(groupInfo.getGroupInfo().getName());
            }
            conversationInfoDto.setSessionId(key);
            conversationInfoDto.setSessionRole(sessionRole);
            conversationInfoDto.setLatestMsg(conversationMessageItemDto);
            list.add(conversationInfoDto);
        }
        this.conversationInfoDtoListSort(list);
        conversationCardDto.setConversationInfoDtoList(list);
        conversationCardDto.setTotalUnread(totalUnread);
        conversationCardDto.setConversationUserInfoDtoMap(conversationUserInfoDtoMap);
        return conversationCardDto;
    }

    /**
     * A向B（私聊或群聊）发送一条消息：插入到A的会话列表，插入到Bs的会话列表，Bs的未读数+1
     * A读取了B（私聊或群聊）的消息：A的未读盒子删除B field
     *
     * @param chatMsg 聊天消息
     */
    @Override
    public void updateLatestMessage(Message chatMsg) {
        MessageRequest messageRequest = chatMsg.getMessageRequest();
        String fromUid = messageRequest.getFrom();
        String toUid = messageRequest.getTo();
        //会话角色码
        Integer sessionRole = messageRequest.getSessionRole();
        ConversationMessageItemDto conversationMessageItemDto = assembleMessageItemDto(messageRequest);
        String json = JSON.toJSONString(conversationMessageItemDto);
        //私聊情况
        if (sessionRole.equals(MessageConstants.MessageCommandType.PRIVATE_MESSAGE)) {

            String fromUidLatestConversationKey = CacheConstants.getLatestConversationKey(fromUid);
            String toUidLatestConversationKey = CacheConstants.getLatestConversationKey(toUid);
            String toUidUnreadKey = CacheConstants.getUnreadKey(toUid);
            //最新一条记录
            redisTemplate.opsForHash().put(fromUidLatestConversationKey, toUid, json);
            redisTemplate.opsForHash().put(toUidLatestConversationKey, fromUid, json);
            //未读数
            redisTemplate.opsForHash().increment(toUidUnreadKey, fromUid, 1L);
        }
        //群聊情况
        else if (sessionRole.equals(MessageConstants.MessageCommandType.GROUP_MESSAGE)) {
            List<String> groupUserUidList = groupUserService.getGroupUserUidList(toUid);
            Set<String> uidSet = new HashSet<>(groupUserUidList);
            //集合去除自己
            uidSet.remove(fromUid);
            for(String userUid:uidSet){
                //更新最新记录
                String userLatestConversationKey = CacheConstants.getLatestConversationKey(userUid);
                String userUnreadKey = CacheConstants.getUnreadKey(userUid);
                redisTemplate.opsForHash().put(userLatestConversationKey, toUid, json);
                //更新未读数
                redisTemplate.opsForHash().increment(userUnreadKey, toUid,1L);
            }
            //给自己更新会话列表
            redisTemplate.opsForHash().put(CacheConstants.getLatestConversationKey(fromUid),
                    toUid, json);
        }


    }

    @Override
    public void readUnreadMessage(String uid, String sessionId) {
        String unreadKey = CacheConstants.getUnreadKey(uid);
        //删除key中的field
        redisTemplate.opsForHash().delete(unreadKey, sessionId);
    }

    @Override
    public void saveGroupConversation(String userUid, GroupInfoEntity groupInfoEntity) {
        ConversationMessageItemDto conversationMessageItemDto = new ConversationMessageItemDto();
        conversationMessageItemDto.setContent(MessageConstants.GROUP_CREATED_MSG);
        conversationMessageItemDto.setType(MessageConstants.MessageCommandType.GROUP_MESSAGE);
        conversationMessageItemDto.setSessionRole(MessageConstants.MessageSessionRoleType.GROUP_CHAT);
        conversationMessageItemDto.setGroupId(groupInfoEntity.getResourceId());
        conversationMessageItemDto.setAvatar(groupInfoEntity.getAvatar());
        conversationMessageItemDto.setNickname(groupInfoEntity.getName());
        conversationMessageItemDto.setTimestamp(groupInfoEntity.getCreateTime().getTime());
        String key = CacheConstants.getLatestConversationKey(userUid);
        redisTemplate.opsForHash().put(key, groupInfoEntity.getResourceId(), JSON.toJSONString(conversationMessageItemDto));
    }

    public void invitedToGroupConversation(String groupUid, String userUid, List<String> uidList) {
        UserInfoVo inviteUser = sysUserService.getUserInfoByUserUid(userUid);
        Map<String, UserInfoVo> userInfoMap = sysUserService.getUserInfoMap(uidList);
        List<String> userNicknameList = userInfoMap.values().stream().map(UserInfoVo::getNickname).collect(Collectors.toList());
        String content = String.format("%s邀请了%s进入了群聊",inviteUser.getNickname(),String.join(",", userNicknameList)) ;
        this.invitedToGroupConversation(groupUid,content);
    }

    public void invitedToGroupConversation(String groupUid, String content) {
        List<String> groupUserUidList = groupUserService.getGroupUserUidList(groupUid);
        this.invitedToGroupConversation(groupUid,groupUserUidList,content);
    }

    @Override
    public void invitedToGroupConversation(String groupUid, List<String> toUidList, String content) {
        ConversationMessageItemDto conversationMessageItemDto = new ConversationMessageItemDto();
        conversationMessageItemDto.setType(MessageConstants.MessageCommandType.GROUP_JOINED_MESSAGE);
        conversationMessageItemDto.setSessionRole(MessageConstants.MessageSessionRoleType.GROUP_CHAT);
        conversationMessageItemDto.setContent(content);
        conversationMessageItemDto.setTimestamp(System.currentTimeMillis());
        conversationMessageItemDto.setGroupId(groupUid);
        String json = JSON.toJSONString(conversationMessageItemDto);
        //写会话列表,未读消息
        for(String uid:toUidList){
            String conversationKey = CacheConstants.getLatestConversationKey(uid);
            String unreadKey = CacheConstants.getUnreadKey(uid);
            redisTemplate.opsForHash().put(conversationKey,groupUid,json);
            redisTemplate.opsForHash().increment(unreadKey,groupUid,1L);
        }
    }

    private ConversationMessageItemDto assembleMessageItemDto(MessageRequest messageRequest) {
        ConversationMessageItemDto conversationMessageItemDto = new ConversationMessageItemDto();
        String fromUid = messageRequest.getFrom();
        Long timestamp = messageRequest.getTime();
        String toUid = messageRequest.getTo();
        String content = messageRequest.getContent();
        String fromNick = messageRequest.getFromNick();
        //功能码
        Integer type = messageRequest.getType();
        //角色码
        Integer sessionRole = messageRequest.getSessionRole();
        conversationMessageItemDto.setType(type);
        conversationMessageItemDto.setSessionRole(sessionRole);
        conversationMessageItemDto.setContent(content);
        conversationMessageItemDto.setTimestamp(timestamp);
        conversationMessageItemDto.setReceiverId(toUid);
        conversationMessageItemDto.setSenderId(fromUid);
        conversationMessageItemDto.setNickname(fromNick);
        return conversationMessageItemDto;
    }

    private void conversationInfoDtoListSort(List<ConversationInfoDto> list) {
        list.sort((o1, o2) -> {
            if (o1.getAdd() && o2.getAdd()) {
                return o1.getLatestMsg().getTimestamp() > o2.getLatestMsg().getTimestamp() ? -1 : 1;
            } else if (o1.getAdd() && !o2.getAdd()) {
                return -1;
            } else if (!o1.getAdd() && o2.getAdd()) {
                return 1;
            } else {
                if (o1.getLatestMsg() != null && o2.getLatestMsg() != null) {
                    return o1.getLatestMsg().getTimestamp() > o2.getLatestMsg().getTimestamp() ? -1 : 1;
                }
                if (o1.getLastOpTs() != null && o2.getLastOpTs() != null) {
                    return o1.getLastOpTs() > o2.getLastOpTs() ? -1 : 1;
                }
                return 0;
            }
        });
    }
}
